package com.kk.permission.utils.callershow;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import rx.Observable;
import rx.Observable.OnSubscribe;
import rx.Subscriber;
import rx.subjects.PublishSubject;
import rx.subjects.SerializedSubject;
import rx.subjects.Subject;

public class RxBus {
    private static volatile RxBus ins;
    private final Subject<Object, Object> bus = new SerializedSubject(PublishSubject.create());
    private final Map<Class<?>, Object> mStickyEventMap = new ConcurrentHashMap();

    public static RxBus getIns() {
        if (ins == null) {
            synchronized (RxBus.class) {
                if (ins == null) {
                    ins = new RxBus();
                }
            }
        }
        return ins;
    }

    public void post(Object obj) {
        this.bus.onNext(obj);
    }

    public void postStickyEvent(Object obj) {
        synchronized (this.mStickyEventMap) {
            this.mStickyEventMap.put(obj.getClass(), obj);
        }
        this.bus.onNext(obj);
    }

    public <T> Observable<T> toObservable(Class<T> cls) {
        return this.bus.ofType(cls);
    }

    public <T> Observable<T> toObservableSticky(final Class<T> cls) {
        synchronized (this.mStickyEventMap) {
            Observable<T> ofType = this.bus.ofType(cls);
            final Object obj = this.mStickyEventMap.get(cls);
            if (obj != null) {
                Observable<T> mergeWith = ofType.mergeWith(Observable.create(new OnSubscribe<T>() {
                    public void call(Subscriber<? super T> subscriber) {
                        if (subscriber != null) {
                            subscriber.onNext(cls.cast(obj));
                        }
                    }
                }));
                return mergeWith;
            }
            return ofType;
        }
    }

    public <T> T getStickyEvent(Class<T> cls) {
        T cast;
        synchronized (this.mStickyEventMap) {
            cast = cls.cast(this.mStickyEventMap.get(cls));
        }
        return cast;
    }

    public <T> T removeStickyEvent(Class<T> cls) {
        T cast;
        synchronized (this.mStickyEventMap) {
            cast = cls.cast(this.mStickyEventMap.remove(cls));
        }
        return cast;
    }

    public void removeAllStickyEvents() {
        synchronized (this.mStickyEventMap) {
            this.mStickyEventMap.clear();
        }
    }
}
